<template>
  <vxe-modal
    v-model="visible"
    :width="width"
    :class-name="dark ? 'darkTheme' : ''"
    :show-header="!dark"
    :z-index="nextZIndex"
    class="dialog"
    :id="id"
    storage
    show-zoom
    resize
    :loading="loading"
    destroy-on-close
    :remember="remember"
    v-bind="dialogAttrs"
    @zoom="handleClickZoom"
    @hide="handleHide"
    @close="handleClose"
    @show="handleShow"
  >
    <!-- title 插槽 -->
    <template #title>
      <slot name="title">
        <i :class="getIcon" />
        {{ title }}
      </slot>
    </template>
    <template #corner>
      <span v-if="type === 3 && cornerShow" name="corner" class="corner">
        <el-tooltip effect="light" content="保存图片">
          <i class="vxe-icon-file-image" @click="handleDownLoad"></i>
        </el-tooltip>
        <el-tooltip effect="light" content="打印">
          <i class="vxe-icon-print" @click="handlePrint" />
        </el-tooltip>
      </span>
      <span v-if="corner.length" name="corner" class="corner">
        <el-tooltip
          effect="light"
          :content="item.content"
          v-for="(item, index) in corner"
          :key="index"
        >
          <i :class="item.icon" @click="handleClickCorner(item)"></i>
        </el-tooltip>
      </span>
    </template>
    <component :is="getComponent" :title="title" slot="default" ref="dark">
      <i class="el-icon-circle-close icon-close" @click="handleCloseIcon"></i>
      <div
        :id="uuid"
        :class="{ view: type === 3 }"
        class="container"
        ref="container"
        :style="getContainerStyle"
      >
        <ele-form
          ref="ele-form"
          :form-desc="formDesc"
          :form-data="formData"
          :is-show-back-btn="isShowBackBtn"
          :is-show-cancel-btn="isShowCancelBtn"
          :visible="visible"
          v-bind="$attrs"
          @input="$emit('input', $event)"
          @cancel="handleCancel"
          v-on="$listeners"
        >
          <!-- 默认插槽 -->
          <template #default>
            <slot />
          </template>

          <!-- 作用域插槽 -->
          <template
            v-for="(formItem, field) of formDesc"
            #[field]="{ formData, props }"
          >
            <slot
              :data="formData[field]"
              :desc="formItem"
              :field="field"
              :formData="formData"
              :name="field"
              :props="props"
              :disabled="formItem._disabled"
              :type="formItem._type"
              :options="formItem._options"
            >
              <component
                :is="formItem._type"
                :ref="field"
                :disabled="formItem._disabled"
                :desc="formItem"
                :form-data="formData"
                :options="formItem._options"
                :readonly="props.readonly"
                :field="field"
                :value="getValue(field)"
                @input="setValue(field, $event)"
              />
            </slot>
          </template>

          <!-- 按钮插槽 -->
          <template #form-btn="{ btns }">
            <div
              class="footer__btn"
              :style="{
                display: showButton || [1, 2].includes(type) ? 'flex' : 'none',
              }"
            >
              <slot :btns="btns" name="form-btn">
                <el-button
                  v-for="(btn, index) of getBtns(btns)"
                  :key="index"
                  v-bind="btn.attrs"
                  @click="btn.click"
                >
                  {{ btn.text }}
                </el-button>
              </slot>
            </div>
          </template>
        </ele-form>
      </div>
    </component>
    <!-- footer插槽 -->
    <template #footer>
      <slot name="footer" />
    </template>
  </vxe-modal>
</template>

<script>
  const cloneDeep = require('clone')
  import VXETable from 'vxe-table'
  import html2canvas from 'html2canvas'
  import '@/utils/table2excel'
  import { v4 as uuidv4 } from 'uuid'

  export default {
    name: 'EleFormDialog',
    inheritAttrs: false,
    model: {
      prop: 'formData',
      event: 'input',
    },
    props: {
      theme: {
        type: String,
        default: 'light',
      },
      cornerShow: {
        type: Boolean,
        default: true,
      },
      corner: {
        type: Array,
        default: () => [],
      },
      remember: {
        type: Boolean,
        default: true,
      },
      showButton: {
        type: Boolean,
        default: false,
      },
      icon: {
        type: String,
        default: '',
      },
      type: {
        type: Number,
        default: 1,
      },
      // 表单数据
      formData: {
        type: Object,
        required: true,
      },
      // 弹窗是否显示
      visible: {
        type: Boolean,
        default: false,
      },
      // 弹框标题
      title: String,
      // 弹窗标题
      width: {
        type: String,
        default: '50%',
      },
      // 弹窗其它属性
      dialogAttrs: Object,
      // 是否显示返回按钮, 这里是 false
      isShowBackBtn: {
        type: Boolean,
        default: false,
      },
      // 是否显示取消按钮, 这里是 true
      isShowCancelBtn: {
        type: Boolean,
        default: true,
      },
      // 表单项
      formDesc: {
        type: Object,
        required: true,
      },
      // ... 其它属性同 vue-ele-form 组件
    },
    data() {
      return {
        nextZIndex: 20,
        initVal: {},
        uuid: uuidv4(),
        loading: true,
        id: 'modal',
      }
    },
    computed: {
      getIcon() {
        const iconMap = {
          1: 'vxe-icon-square-plus',
          2: 'vxe-icon-edit',
          3: 'el-icon-view',
        }

        return this.icon || iconMap[this.type]
      },
      dark() {
        return this.theme === 'dark'
      },
      getComponent() {
        return this.dark ? 'dv-border-box-11' : 'template'
      },
      getContainerStyle() {
        return {
          padding: `${this.dark ? 80 : 10}px 15px ${
            this.showButton || [1, 2].includes(this.type) ? '60px' : '10px'
          }`,
        }
      },
    },
    watch: {
      // 当关闭时, 清空数据
      visible: {
        handler(val) {
          if (!val) {
            this.$emit('input', cloneDeep(this.initVal))
          } else {
            this.id = this.title
            this.nextZIndex = VXETable.config.nextZIndex
            this.$nextTick(() => {
              setTimeout(() => {
                this.$refs['ele-form'].$refs.form.clearValidate()
                this.loading = false

                new ResizeObserver(() => {
                  this.$refs?.dark?.initWH && this.$refs?.dark?.initWH()
                }).observe(this.$refs.container)
              }, 50)
              this.$nextTick(() => {
                this.initVal = cloneDeep(this.formData)
              })
            })
          }
        },
        immediate: true,
      },
    },
    methods: {
      handleCloseIcon() {
        this.$emit('update:visible', false)
        this.handleCancel()
      },
      handleClickCorner(item) {
        this.$emit('corner-click', item)
      },
      handleCancel() {
        this.$emit('cancel')
        this.$emit('closed')
      },
      handleHide() {
        this.loading = true
      },
      handleClickZoom() {
        this.$emit('zoom')
      },
      async handleDownLoad() {
        const img = await this.getCanvasImg()
        this.downloadBase64Img(
          img,
          `${this.$router.currentRoute.meta.title}详情`
        )
        this.$modal.closeLoading()
      },
      downloadBase64Img(base64Data, filename) {
        const link = document.createElement('a')
        link.href = base64Data
        link.download = filename
        document.body.appendChild(link)
        link.click()
        document.body.removeChild(link)
      },
      async getCanvasImg() {
        this.$modal.loading('请稍候...')
        const html = document.getElementById(this.uuid)
        const canvas = await html2canvas(html, {
          allowTaint: true,
          useCORS: true,
          scale: 1,
          height: html.scrollHeight,
          windowHeight: html.scrollHeight + 1000,
        })
        return canvas.toDataURL('image/png')
      },
      async handlePrint() {
        const img = await this.getCanvasImg()
        VXETable.print({
          sheetName: `${this.$router.currentRoute.meta.title}详情`,
          style: `img {width: 100%;height: 100%;}`,
          content: `<img src="${img}">`,
        })
        this.$modal.closeLoading()
      },
      handleClose() {
        this.$emit('closed')
      },
      handleShow() {
        this.$emit('open')
      },
      getValue(val) {
        if (this.$refs['ele-form']) {
          return this.$refs['ele-form'].getValue(val)
        }
      },
      setValue(field, $event) {
        this.$nextTick(() => {
          this.$refs['ele-form'].setValue(field, $event)
        })
      },
      getBtns(btns) {
        return btns
          .map((item) => {
            item.click.bind(this.$refs.form)
            return item
          })
          .reverse()
      },
    },
  }
</script>

<style lang="scss">
  .dialog {
    overflow: hidden;
    background-image: radial-gradient(transparent 1px, rgba(0, 0, 0, 0.3) 1px);
    background-size: 4px 4px;
    border-radius: 5px;
    backdrop-filter: saturate(50%) blur(4px);

    .el-col-22 {
      width: 100%;

      .el-row {
        display: flex;
        flex-wrap: wrap;
      }
    }

    &.is--visible.is--mask:before {
      background-color: transparent;
    }

    .vxe-modal {
      &--content {
        padding: 0 !important;
        white-space: inherit !important;
      }

      &--box {
        transform: scale(1, 1);
      }
    }

    .icon-close {
      display: none;
    }
  }
</style>

<style lang="scss" scoped>
  .container {
    width: 100%;
    max-height: 90vh;
    overflow-y: scroll !important;
  }

  .corner i {
    display: inline-block;
    margin-left: 10px;
    cursor: pointer;

    &:hover {
      color: #409eff;
    }

    &:last-child {
      padding-right: 0;
    }
  }

  .footer__btn {
    position: fixed;
    right: 0;
    bottom: 0;
    left: 0;
    z-index: 99;
    display: flex;
    justify-content: flex-end;
    padding: 7px 20px;
    background: #fff;
    border-top: 1px solid #eee;
  }

  ::v-deep {
    polyline {
      fill: #0f1f39 !important;
    }
  }
</style>
